﻿//Created by Action Script Viewer - http://www.buraks.com/asv
package Engine.Classes {
    import Engine.Helpers.*;
    import __AS3__.vec.*;
    import Engine.*;

	/**
	 * 地图上两点之间路径的计算
	 */
    public class Pathfinder {

        protected static const HEURISTIC:Number = 0.9;
        protected static const COLLIDE_DIRTY:int = 2;
        protected static const COLLIDE_FALSE:int = 0;
        protected static const COLLIDE_TRUE:int = 1;

        protected var m_distance:Vector.<Number> = null;
        protected var m_score:Vector.<Number> = null;
        protected var m_isPathable:Vector.<Boolean> = null;
        protected var m_isCollide:Vector.<int> = null;
        protected var m_ignoredSpace:Object = null;
        protected var m_prevPos:Vector.<Number> = null;
        protected var m_openList:Array = null;
        protected var m_sizeX:int = -1;
        protected var m_sizeY:int = -1;
        protected var m_startPos:Number = -1;
        protected var m_endPos:Number = -1;
        protected var m_endX:int = -1;
        protected var m_endY:int = -1;
        protected var m_bestLocation:Number = -1;
        protected var m_ignoreList:Array;
        protected var m_colData:CollisionLookup;
        protected var m_colMap:CollisionMap;
        protected var m_minDist:Number;

        public function Pathfinder(_arg1:int, _arg2:int, _arg3:CollisionMap){
            this.m_sizeX = _arg1;
            this.m_sizeY = _arg2;
            this.m_colMap = _arg3;
            this.m_distance = new Vector.<Number>((this.m_sizeX * this.m_sizeY), true);
            this.m_score = new Vector.<Number>((this.m_sizeX * this.m_sizeY), true);
            this.m_isPathable = new Vector.<Boolean>((this.m_sizeX * this.m_sizeY), true);
            this.m_isCollide = new Vector.<int>((this.m_sizeX * this.m_sizeY), true);
            this.m_prevPos = new Vector.<Number>((this.m_sizeX * this.m_sizeY), true);
            this.m_ignoredSpace = new Object();
            var _local4:int;
            _local4 = 0;
            while (_local4 < (this.m_sizeX * this.m_sizeY)) {
                this.m_isPathable[_local4] = false;
                this.m_isCollide[_local4] = COLLIDE_DIRTY;
                _local4++;
            };
            this.m_openList = [];
        }
        public function setPathable(_arg1:int, _arg2:int, _arg3:Boolean=true):void{
            this.m_isPathable[((_arg2 * this.m_sizeX) + _arg1)] = _arg3;
        }
        public function findPath(_arg1:int, _arg2:int, _arg3:int, _arg4:int, _arg5:Array, _arg6:Array=null, _arg7:Boolean=false, _arg8:Number=0.1):Boolean{
            var _local11:Number;
            var _local12:int;
            var _local13:int;
            var _local14:Boolean;
            var _local17:Boolean;
            var _local9:Boolean;
            var _local10:Boolean;
            var _local15:int;
            var _local16:int = ((this.m_sizeX + this.m_sizeY) * 20);
            this.m_minDist = _arg8;
            this.m_ignoreList = _arg6;
            this.clear();
            this.setupIgnoredSpace();
            _arg1 = ((_arg1 >= this.m_sizeX)) ? this.m_sizeX : _arg1;
            _arg2 = ((_arg2 >= this.m_sizeY)) ? this.m_sizeY : _arg2;
            _arg1 = ((_arg1 < 0)) ? 0 : _arg1;
            _arg2 = ((_arg2 < 0)) ? 0 : _arg2;
            _arg3 = ((_arg3 >= this.m_sizeX)) ? this.m_sizeX : _arg3;
            _arg4 = ((_arg4 >= this.m_sizeY)) ? this.m_sizeY : _arg4;
            _arg3 = ((_arg3 < 0)) ? 0 : _arg3;
            _arg4 = ((_arg4 < 0)) ? 0 : _arg4;
            this.m_endX = _arg3;
            this.m_endY = _arg4;
            this.m_startPos = ((_arg2 * this.m_sizeX) + _arg1);
            this.m_endPos = ((_arg4 * this.m_sizeX) + _arg3);
            this.m_distance[this.m_startPos] = 0;
            this.m_score[this.m_startPos] = 0;
            this.m_isCollide[this.m_startPos] = COLLIDE_DIRTY;
            if ((((this.m_minDist < 1)) && (((!(this.m_isPathable[this.m_endPos])) || (!(this.canPath(_arg3, _arg4))))))){
                _local9 = true;
            };
            this.canPath(_arg1, _arg2);
            this.m_openList.push(this.m_startPos);
            while (!(_local9)) {
                if (this.m_openList.length == 0){
                    if (this.m_bestLocation >= 0){
                        this.pathBack(this.m_bestLocation, this.m_startPos, _arg5);
                    };
                    _local9 = true;
                } else {
                    _local11 = this.m_openList.shift();
                    if (((!((this.m_startPos == _local11))) && ((((this.m_bestLocation == -1)) || ((this.m_score[this.m_bestLocation] > this.m_score[_local11])))))){
                        this.m_bestLocation = _local11;
                    };
                    _local12 = (_local11 % this.m_sizeX);
                    _local13 = ((_local11 - _local12) / this.m_sizeX);
                    _local14 = false;
                    _local17 = !(this.canPath(_local12, _local13));
                    _local14 = this.addNode((_local12 + 1), _local13, _local11, _local17, 1);
                    _local14 = ((this.addNode((_local12 - 1), _local13, _local11, _local17, 1)) || (_local14));
                    _local14 = ((this.addNode(_local12, (_local13 + 1), _local11, _local17, 1)) || (_local14));
                    _local14 = ((this.addNode(_local12, (_local13 - 1), _local11, _local17, 1)) || (_local14));
                    if (!_arg7){
                        _local14 = ((this.addNode((_local12 + 1), (_local13 + 1), _local11, _local17, Math.SQRT2, 1, 1)) || (_local14));
                        _local14 = ((this.addNode((_local12 - 1), (_local13 + 1), _local11, _local17, Math.SQRT2, -1, 1)) || (_local14));
                        _local14 = ((this.addNode((_local12 + 1), (_local13 - 1), _local11, _local17, Math.SQRT2, 1, -1)) || (_local14));
                        _local14 = ((this.addNode((_local12 - 1), (_local13 - 1), _local11, _local17, Math.SQRT2, -1, -1)) || (_local14));
                    };
                    if (_local14){
                        _local9 = true;
                        _local10 = true;
                        this.pathBack(this.m_bestLocation, this.m_startPos, _arg5);
                    };
                    _local15++;
                    if (_local15 > _local16){
                        this.m_openList = [];
                    };
                };
            };
            return (_local10);
        }
        protected function addNode(_arg1:int, _arg2:int, _arg3:Number, _arg4:Boolean, _arg5:Number, _arg6:int=0, _arg7:int=0):Boolean{
            var _local8:int;
            var _local9:int;
            var _local10:int;
            var _local11:Number;
            var _local12:Boolean;
            var _local13:Boolean = (((((((_arg1 >= 0)) && ((_arg1 < this.m_sizeX)))) && ((_arg2 >= 0)))) && ((_arg2 < this.m_sizeY)));
            var _local14:Number = ((_arg2 * this.m_sizeX) + _arg1);
            var _local15:Boolean;
            if (((_local13) && ((this.m_score[_local14] == -1)))){
                if (_arg4){
                    _local15 = true;
                } else {
                    if (!this.canPath(_arg1, _arg2)){
                        _local15 = false;
                    } else {
                        if (_arg5 != 1){
                            _local15 = ((this.canPath((_arg1 - _arg6), _arg2)) && (this.canPath(_arg1, (_arg2 - _arg7))));
                        };
                        if (((((_local15) && (!(this.m_isPathable[_local14])))) && (this.m_isPathable[_arg3]))){
                            _local15 = false;
                        };
                    };
                };
                if (_local15){
                    this.m_distance[_local14] = (this.m_distance[_arg3] + _arg5);
                    _local11 = Math.sqrt((((_arg1 - this.m_endX) * (_arg1 - this.m_endX)) + ((_arg2 - this.m_endY) * (_arg2 - this.m_endY))));
                    this.m_score[_local14] = (this.m_distance[_local14] + (HEURISTIC * _local11));
                    this.m_prevPos[_local14] = _arg3;
                    if ((((_local11 < this.m_minDist)) || ((_local14 == this.m_endPos)))){
                        _local12 = true;
                        if ((((((_local14 == this.m_endPos)) || ((this.m_bestLocation == -1)))) || (((this.m_score[this.m_bestLocation] - this.m_distance[this.m_bestLocation]) > (HEURISTIC * _local11))))){
                            this.m_bestLocation = _local14;
                        };
                    } else {
                        _local8 = 0;
                        _local9 = this.m_openList.length;
                        _local10 = ((_local8 + _local9) >> 1);
                        while (_local8 < _local9) {
                            if (this.m_score[_local14] < this.m_score[this.m_openList[_local10]]){
                                _local9 = _local10;
                                _local10 = ((_local8 + _local9) >> 1);
                            } else {
                                if (this.m_score[_local14] > this.m_score[this.m_openList[_local10]]){
                                    _local8 = (_local10 + 1);
                                    _local10 = ((_local8 + _local9) >> 1);
                                } else {
                                    break;
                                };
                            };
                        };
                        this.m_openList.splice(_local10, 0, _local14);
                    };
                };
            };
            return (_local12);
        }
        protected function canPath(_arg1:int, _arg2:int):Boolean{
            var _local3:int;
            var _local4:Boolean;
            var _local5:Number = ((_arg2 * this.m_sizeX) + _arg1);
            if (this.m_isCollide[_local5] == COLLIDE_DIRTY){
                if (this.m_colData == null){
                    this.m_colData = new CollisionLookup();
                };
                this.m_colData.init(_arg1, _arg2, (_arg1 + 1), (_arg2 + 1));
                this.m_colData.flags = Constants.COLLISION_AVATAR;
                this.m_isCollide[_local5] = (this.m_colMap.checkCollisionForCell(this.m_colData)) ? COLLIDE_TRUE : COLLIDE_FALSE;
            };
            if (this.m_isCollide[_local5] == COLLIDE_TRUE){
                if (this.m_ignoredSpace[_local5] == COLLIDE_DIRTY){
                    if (this.m_colData == null){
                        this.m_colData = new CollisionLookup();
                    };
                    this.m_colData.init(_arg1, _arg2, (_arg1 + 1), (_arg2 + 1));
                    this.m_colData.ignoreObjects = this.m_ignoreList;
                    this.m_colData.flags = Constants.COLLISION_AVATAR;
                    this.m_ignoredSpace[_local5] = (this.m_colMap.checkCollisionForCell(this.m_colData)) ? COLLIDE_TRUE : COLLIDE_FALSE;
                };
                if (((this.m_ignoredSpace.hasOwnProperty(_local5)) && ((this.m_ignoredSpace[_local5] == COLLIDE_FALSE)))){
                    _local4 = true;
                } else {
                    _local4 = false;
                };
            };
            return (_local4);
        }
        protected function clear():void{
            var _local1:int;
            var _local2:Number = (this.m_sizeX * this.m_sizeY);
            _local1 = 0;
            while (_local1 < _local2) {
                this.m_score[_local1] = -1;
                _local1++;
            };
            if (this.m_openList.length > 0){
                this.m_openList = [];
            };
            this.m_ignoredSpace = new Object();
            this.m_bestLocation = -1;
        }
        protected function pathBack(_arg1:Number, _arg2:Number, _arg3:Array):void{
            var _local4:int;
            var _local5:int;
            var _local6:Number = _arg1;
            while (_local6 != -1) {
                _local4 = (_local6 % this.m_sizeX);
                _local5 = ((_local6 - _local4) / this.m_sizeX);
                _arg3.push(new Vector3(_local4, _local5));
                if (_local6 == _arg2){
                    break;
                };
                _local6 = this.m_prevPos[_local6];
            };
            _arg3.reverse();
        }
        public function setCollisionMapDirty(_arg1:int, _arg2:int, _arg3:int, _arg4:int):void{
            var _local5:int;
            var _local6:int;
            var _local7:Number = 0;
            _arg2 = ((_arg2 > this.m_sizeX)) ? this.m_sizeX : _arg2;
            _arg4 = ((_arg4 > this.m_sizeY)) ? this.m_sizeY : _arg4;
            _arg1 = ((_arg1 < 0)) ? 0 : _arg1;
            _arg3 = ((_arg3 < 0)) ? 0 : _arg3;
            _local6 = _arg3;
            while (_local6 < _arg4) {
                _local7 = (_local6 * this.m_sizeX);
                _local5 = _arg1;
                while (_local5 < _arg2) {
                    this.m_isCollide[(_local7 + _local5)] = COLLIDE_DIRTY;
                    _local5++;
                };
                _local6++;
            };
        }
        protected function setupIgnoredSpace():void{
            var _local1:int;
            var _local2:int;
            var _local3:int;
            var _local4:WorldObject;
            var _local5:Vector3;
            var _local6:Vector3;
            var _local7:Number;
            _local3 = 0;
            while (_local3 < this.m_ignoreList.length) {
                _local4 = this.m_ignoreList[_local3];
                _local5 = _local4.getPositionNoClone();
                _local6 = _local4.getSizeNoClone();
                _local2 = _local5.y;
                while (_local2 < (_local5.y + _local6.y)) {
                    _local7 = (_local2 * this.m_sizeX);
                    _local1 = _local5.x;
                    while (_local1 < (_local5.x + _local6.x)) {
                        this.m_ignoredSpace[(_local7 + _local1)] = COLLIDE_DIRTY;
                        _local1++;
                    };
                    _local2++;
                };
                _local3++;
            };
        }
        protected function printSurroundings(_arg1:int, _arg2:int):void{
            var _local3:int;
            var _local4:int;
            var _local5:Number = 0;
            trace(((("printing area surrounding " + _arg1) + ", ") + _arg2));
            _arg1 = ((_arg1 >= (this.m_sizeX - 3))) ? (this.m_sizeX - 3) : _arg1;
            _arg2 = ((_arg2 >= (this.m_sizeY - 3))) ? (this.m_sizeY - 3) : _arg2;
            _arg1 = ((_arg1 < 2)) ? 2 : _arg1;
            _arg2 = ((_arg2 < 2)) ? 2 : _arg2;
            var _local6 = "";
            var _local7 = "";
            var _local8 = "";
            var _local9 = "";
            _local4 = (_arg2 + 2);
            while (_local4 >= (_arg2 - 2)) {
                _local5 = (_local4 * this.m_sizeX);
                _local7 = "";
                _local9 = "";
                _local3 = (_arg1 - 2);
                while (_local3 < (_arg1 + 3)) {
                    _local7 = (_local7 + this.m_isCollide[(_local5 + _local3)]);
                    _local9 = (_local9 + this.m_ignoredSpace[(_local5 + _local3)]);
                    _local3++;
                };
                _local8 = ((_local8 + "\n") + _local9);
                _local6 = ((_local6 + "\n") + _local7);
                _local4--;
            };
            trace(("cmap = \n" + _local6));
            trace(("imap = \n" + _local8));
        }

    }
}//package Engine.Classes 
